package dongshi.daddy.aviator;

import com.alibaba.fastjson.JSON;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AaviatorDemo {
    public static void main(String[] args) throws IOException {
        // 计算表达式
        Long r = (Long) AviatorEvaluator.execute("2 * (3 + 5)");
        System.out.println("r: " + r);
        // 为了提升性能，往往先编译表达式，然后可以反复执行，进行表达式求值
        Expression expression = AviatorEvaluator.compile("2 * (3 + 5)");
        Long r1 = (Long) expression.execute();
        System.out.println("r1: " + r1);

        // 返回 hello world
        String r3 = (String) AviatorEvaluator.execute("'hello' + ' world'");
        System.out.println("r3: " + r3);
        // 返回 true
        Boolean r4 = (Boolean) AviatorEvaluator.execute("100 > 80 && 30 < 40");
        System.out.println("r4: " + r4);
        // 三元表达式，返回 30
        Long r5 = (Long) AviatorEvaluator.execute("100 > 80 ? 30 : 40");
        System.out.println("r5: " + r5);
        // 正则表达式，正则表达式放在//之间，返回 true
        Boolean r6 = (Boolean) AviatorEvaluator.execute("'hello' =~ /[\\w]+/");
        System.out.println("r6: " + r6);

        // 跟其他表达式引擎一样，aviator也是支持表达式求值时传入参数的：
        Long a = 12L;
        Boolean r7 = (Boolean) AviatorEvaluator.exec("a > 10", a);
        System.out.println("r7: " + r7);

        // 参数也可以是一个列表，如下：
        List<Long> a0 = new ArrayList<>();
        a0.add(12L);
        a0.add(20L);
        Boolean r8 = (Boolean) AviatorEvaluator.exec("a0[0] > 10", a0);
        System.out.println("r8: " + r8);

        Person a1 = new Person("movee", 25);
        Boolean r9 = (Boolean) AviatorEvaluator.exec("a1.age > 10", a1);
        System.out.println("r9: " + r9);

        // 跟一般地，aviator会将参数放到一个map中
        Map<String, Object> env = new HashMap<>();
        env.put("person", new Person("movee1111", 25));
        env.put("a", 20L);
        Object result = AviatorEvaluator.execute("person.name", env); // 从map中直接拿到person key然后调用其getName方法
        System.out.println(result);

        // 这样一来，aviator可以非常方便的从json字符串中提取子json字符串
        String jsonStr = "{\"a\":{\"b\":[{\"x\":3},{\"x\":4}]}}";
//        JSONObject jsonObj = new JSONObject(jsonStr);
        Map map = JSON.parseObject(jsonStr, Map.class);
        // 结果返回 3
        Object value = AviatorEvaluator.execute("a.b[0]['x']", map);
        System.out.println("value is: " + value);

        // 使用函数
        // aviator已经提供了很多开箱即用的函数了：
        // 返回4
        Long r10 = (Long) AviatorEvaluator.execute("math.round(4.3)");
        System.out.println("r10 is: " + r10);
        // 返回5
        Long r11 = (Long) AviatorEvaluator.execute("string.length('hello')");
        System.out.println("r11 is: " + r11);
        // 返回一个ArrayList：[1,2,3]
        Object r12 = AviatorEvaluator.execute("seq.list(1,2,3)");
        System.out.println("r12 is: " + r12);

        // 我们也可以自定义一个java函数，自己编写一个类，继承aviator的AbstractFunction类，然后实现相应的方法即可：
        // 然后就可以注册到aviator中，像使用内置函数一样使用自定义函数：
        // 注册
        AviatorEvaluator.addFunction(new AddFunction());
        // 使用
        long sum = (Long) AviatorEvaluator.getInstance().execute("add(3,4)");
        System.out.println("sum is: " + sum);


        // aviatorScript脚本
        // aviator已经升级为一个脚本语言，所以不仅仅能进行表达式求值，还可以执行脚本程序。
        // 返回1
        Object r13 = AviatorEvaluator.execute("if (true) { return 1; } else { return 2; }");
        System.out.println("r13 is: " + r13);

        // aviatorScript脚本一般放到独立的脚本文件中，文件名后缀一般为.av 例如，我们编写一个hello.av脚本文件，内容为：
        /*
        if (a > 10) {
            return 10;
        } else {
            return a;
        }

         */
        Map<String, Object> env1 = new HashMap<>();
        env1.put("a", 30);
        Expression exp = AviatorEvaluator.getInstance().compileScript("./hello.av", true);
        Object result1 = exp.execute(env);
        System.out.println("result1 is: " + result1);
    }
    static class Person {
        private String name;
        private Integer age;

        public Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public Integer getAge() {
            return age;
        }
    }

}


